from typing import override
import uuid
from django.db import models
from system.models import CoreModel
from django.utils import timezone
from django_celery_beat.models import CrontabSchedule, IntervalSchedule, ClockedSchedule

# Create your models here.


# 任务类型选项
TASK_TYPE_CHOICES = (
    ('crontab', '周期任务'),
    ('interval', '定时任务'),
    ('clock', '时钟任务'),
    ('once', '一次性任务'),
)

# 任务状态选项
TASK_STATUS_CHOICES = (
    ('pending', '等待执行'),
    ('running', '执行中'),
    ('completed', '已完成'),
    ('failed', '执行失败'),
    ('canceled', '已取消'),
)

# 定时任务时间单位选项
INTERVAL_UNIT_CHOICES = (
    ('seconds', '秒'),
    ('minutes', '分钟'),
    ('hours', '小时'),
    ('days', '天'),
)

class TaskDefinition(CoreModel):
    """任务定义 - 直接关联Celery调度表"""
    name = models.CharField(max_length=255, verbose_name='任务名称')
    task_type = models.CharField(max_length=20, choices=TASK_TYPE_CHOICES, verbose_name='任务类型')
    
    # 直接外键关联Celery调度表
    crontab = models.ForeignKey(
        CrontabSchedule, 
        null=True, 
        blank=True, 
        on_delete=models.CASCADE,
        verbose_name='Crontab调度',
        help_text='周期任务调度配置'
    )
    interval = models.ForeignKey(
        IntervalSchedule, 
        null=True, 
        blank=True, 
        on_delete=models.CASCADE,
        verbose_name='Interval调度',
        help_text='间隔任务调度配置'
    )
    clocked = models.ForeignKey(
        ClockedSchedule, 
        null=True, 
        blank=True, 
        on_delete=models.CASCADE,
        verbose_name='Clocked调度',
        help_text='时钟任务调度配置'
    )

    class Meta:
        db_table = 'task_definition'
        verbose_name = '任务定义'
        verbose_name_plural = '任务定义'
    
    def clean(self):
        """校验调度配置"""
        from django.core.exceptions import ValidationError
        
        # 根据任务类型校验必须设置的调度
        if self.task_type == 'crontab' and not self.crontab:
            raise ValidationError('周期任务必须设置Crontab调度')
        elif self.task_type == 'interval' and not self.interval:
            raise ValidationError('间隔任务必须设置Interval调度')
        elif self.task_type == 'clock' and not self.clocked:
            raise ValidationError('时钟任务必须设置Clocked调度')
        
        # 确保只设置了一种调度
        schedules = [self.crontab, self.interval, self.clocked]
        if sum(1 for s in schedules if s is not None) > 1:
            raise ValidationError('只能设置一种调度类型')
    
    @override
    def save(self, *args, **kwargs):
        self.clean()
        super().save(*args, **kwargs)
    
    @override
    def delete(self, using=None, keep_parents=False):
        """删除时同步删除关联的调度表"""
        # 检查是否有关联的任务
        if self.tasks.exists():
            raise Exception("任务定义下有任务，无法删除")
        
        # 删除关联的调度(如果不被其他任务使用)
        schedules_to_delete = []
        if self.crontab:
            schedules_to_delete.append(self.crontab)
        if self.interval:
            schedules_to_delete.append(self.interval)
        if self.clocked:
            schedules_to_delete.append(self.clocked)
        
        # 先删除TaskDefinition
        result = super().delete(using, keep_parents)
        
        # 再删除调度(如果没有其他引用)
        for schedule in schedules_to_delete:
            try:
                # 检查是否还有其他TaskDefinition使用此调度
                if hasattr(schedule, 'taskdefinition_set') and not schedule.taskdefinition_set.exists():
                    schedule.delete()
            except Exception:
                pass
        
        return result

    def __str__(self):
        return self.name

class Tasks(CoreModel):
    """任务列表"""
    name = models.CharField(max_length=255, default=uuid.uuid4, unique=True, verbose_name='任务名称')
    task_func = models.CharField(max_length=255, verbose_name='任务函数')
    # 任务参数（JSON格式）
    task_args = models.JSONField(default=dict, blank=True, verbose_name='位置参数')
    task_kwargs = models.JSONField(default=dict, blank=True, verbose_name='关键字参数')
    # 任务状态
    enabled = models.BooleanField(default=True, verbose_name='是否启用')
    # 关联的任务定义
    task_definition = models.ForeignKey(TaskDefinition, on_delete=models.CASCADE, 
                                        related_name='tasks',verbose_name='任务定义')
    # 关联的Celery任务ID
    celery_task_id = models.CharField(max_length=50, null=True, blank=True, verbose_name='Celery任务ID')

    class Meta:
        db_table = 'tasks'
        verbose_name = '任务'
        verbose_name_plural = '任务'

    def __str__(self):
        return self.name